package com.hnust.root.common.base.exception;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSException;
import com.hnust.root.common.base.response.BaseRestController;
import com.hnust.root.common.base.response.BaseResult;
import com.hnust.root.common.constant.ResultConstant;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * @Author zhusir
 * @Date 2019/1/26
 * @Desc 统一异常处理
 */
@ControllerAdvice
public class AllControllerAdvice extends BaseRestController {
    private static final Log LOGGER = LogFactory.get();

    /**
     * 应用到所有@RequestMapping注解方法，在其执行之前初始化数据绑定器
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
    }

    /**
     * 把值绑定到Model中，使全局@RequestMapping可以获取到该值
     */
    @ModelAttribute
    public void addAttributes(Model model) {
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public BaseResult<String> serverInternalError(Exception e) {
        LOGGER.info("接口出现严重异常: {}", getStackTrace(e));
        return new BaseResult<>(HttpStatus.OK.value(),
                ResultConstant.SERVER_FIAL_CODE,
                ResultConstant.SERVER_FIAL_MSG,
                e.getMessage());
    }

    // 捕捉shiro的异常
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(ShiroException.class)
    public BaseResult handle401(ShiroException e) { return fillFailData("shiro的异常"); }

    // 捕捉UnauthorizedException
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(UnauthorizedException.class)
    public BaseResult handle401() { return fillFailData("用户验证失败"); }

    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(AuthenticationException.class)
    public BaseResult tokenInvaliad() { return fillFailData("Token无效"); }

    // 处理用户被禁用异常
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ForbiddenUserException.class)
    public BaseResult handleUserBan() { return fillFailData("用户已被禁用"); }

    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(DBException.class)
    public BaseResult<String> dataError(Exception e) {
       return fillFailData(ResultConstant.DATABASE_FAIL_MSG);
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(BusinessException.class)
    public BaseResult<String> logicError(Exception e) {
        return fillFailData(e.getMessage());
    }


    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public BaseResult<String> fileOpError(Exception e) {
        if (e instanceof OSSException || e instanceof ClientException) {
            return fillFailData(ResultConstant.FILE_OP_FAIL);
        } else {
            return baseResult(e);
        }
    }
    //打印异常堆栈的详细信息,输出到日志文件
    private static String getStackTrace(Throwable throwable)
    {
        StringWriter sw = new StringWriter();
        try (PrintWriter pw = new PrintWriter(sw)) {
            throwable.printStackTrace(pw);
            return sw.toString();
        }
    }

    private BaseResult<String> baseResult(Exception e) {
        return new BaseResult<>(HttpStatus.OK.value(),
                ResultConstant.SERVER_FIAL_CODE,
                ResultConstant.SERVER_FIAL_MSG,
                e.getMessage());
    }
}
